﻿using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.OpenApi.Models;
using RuoVea.ExSwagger;
using Swashbuckle.AspNetCore.Filters;
using Swashbuckle.AspNetCore.SwaggerGen;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;

namespace RuoVea.ExSwagger;

/// <summary>
/// 
/// </summary>
public static class SwaggerExtensions
{
    /// <summary>
    /// 
    /// </summary>
    /// <param name="services"></param>
    /// <param name="versions">版本号</param>
    /// <param name="isAuthor">是否授权</param>
    /// <param name="schemeName">默认 Bearer </param>
    public static IServiceCollection AddSwaggerGen(this IServiceCollection services, List<DocVersions> versions, bool isAuthor = false, string schemeName = "Bearer")
    {
        if (services == null) throw new ArgumentNullException(nameof(services));

        services.AddSwaggerGen(c =>
        {
            foreach (var v in versions)
            {
                c.SwaggerDoc(v.Version, new OpenApiInfo()
                {
                    Title = $"{v.Title} - {RuntimeInformation.FrameworkDescription}",
                    Version = v.Version,
                });
            }
            c.CustomOperationIds(apiDesc =>
            {
                var controllerAction = apiDesc.ActionDescriptor as ControllerActionDescriptor;
                return controllerAction.ControllerName + "-" + controllerAction.ActionName;
            });
            c.DocumentFilter<SwaggerApi>();

            if (isAuthor)
            {
                c.AddSecurityDefinition(schemeName, new OpenApiSecurityScheme
                {
                    Type = SecuritySchemeType.Http,
                    Name = "Authorization",
                    Description = "JWT Authorization header using the Bearer scheme.",
                    BearerFormat = "JWT",
                    Scheme = schemeName.ToLower(),
                    In = ParameterLocation.Header,
                });

                c.AddSecurityRequirement(new OpenApiSecurityRequirement {{
                    new OpenApiSecurityScheme{
                        Reference =new  OpenApiReference{ Type=ReferenceType.SecurityScheme, Id=schemeName }
                    },
                    new string[]{ }
                }
            });

                c.OrderActionsBy((apidesc) => apidesc.RelativePath);
                ////向swagger添加header参数
                //options.OperationFilter<AddRequiredHeaderParameter>();
                //开启加权锁
                c.OperationFilter<AddResponseHeadersFilter>();
                c.OperationFilter<AppendAuthorizeToSummaryOperationFilter>();
                // 在header中添加token，传递到后台
                c.OperationFilter<SecurityRequirementsOperationFilter>();
                c.OrderActionsBy((apiDesc) => $"{apiDesc.ActionDescriptor.RouteValues["controller"]}");

                try { Directory.GetFiles(AppDomain.CurrentDomain.BaseDirectory, "*.xml").ToList().ForEach(file => { c.IncludeXmlComments(file, true); }); } catch { }

            }
        });
        return services;
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="services"></param>
    /// <param name="versions">版本号</param>
    /// <param name="swaggerDoc">配置信息</param>
    /// <param name="isAuthor">是否授权</param>
    /// <param name="schemeName">默认 Bearer </param>
    public static IServiceCollection AddSwaggerGen(this IServiceCollection services, List<DocVersions> versions, SwaggerDocOptions swaggerDoc, bool isAuthor = false, string schemeName = "Bearer")
    {
        if (services == null) throw new ArgumentNullException(nameof(services));

        services.AddSwaggerGen(c =>
        {
            foreach (var v in versions)
            {
                c.SwaggerDoc(v.Version, new OpenApiInfo()
                {
                    Title = $"{v.Title} -- {swaggerDoc.Title} - {RuntimeInformation.FrameworkDescription}",
                    Version = v.Version,
                    TermsOfService = new Uri(swaggerDoc.TermsOfService),
                    Description = swaggerDoc.Description,
                    Contact = new OpenApiContact { Name = swaggerDoc.ContactName, Email = swaggerDoc.ContactEmail, Url = new Uri(swaggerDoc.ContactUrl) },
                }
                               );
            }
            c.CustomOperationIds(apiDesc =>
            {
                var controllerAction = apiDesc.ActionDescriptor as ControllerActionDescriptor;
                return controllerAction.ControllerName + "-" + controllerAction.ActionName;
            });
            c.DocumentFilter<SwaggerApi>();

            if (isAuthor)
            {
                c.AddSecurityDefinition(schemeName, new OpenApiSecurityScheme
                {
                    Type = SecuritySchemeType.Http,
                    Name = "Authorization",
                    Description = "JWT Authorization header using the Bearer scheme.",
                    BearerFormat = "JWT",
                    Scheme = schemeName.ToLower(),
                    In = ParameterLocation.Header,
                });

                c.AddSecurityRequirement(new OpenApiSecurityRequirement {{
                    new OpenApiSecurityScheme{
                        Reference =new  OpenApiReference{ Type=ReferenceType.SecurityScheme, Id=schemeName }
                    },
                    new string[]{ }
                }
            });

                c.OrderActionsBy((apidesc) => apidesc.RelativePath);
                ////向swagger添加header参数
                //options.OperationFilter<AddRequiredHeaderParameter>();
                //开启加权锁
                c.OperationFilter<AddResponseHeadersFilter>();
                c.OperationFilter<AppendAuthorizeToSummaryOperationFilter>();
                // 在header中添加token，传递到后台
                c.OperationFilter<SecurityRequirementsOperationFilter>();
                c.OrderActionsBy((apiDesc) => $"{apiDesc.ActionDescriptor.RouteValues["controller"]}");

                try { Directory.GetFiles(AppDomain.CurrentDomain.BaseDirectory, "*.xml").ToList().ForEach(file => { c.IncludeXmlComments(file, true); }); } catch { }

            }
        });
        return services;
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="services"></param>
    /// <param name="versions">版本</param>
    /// <param name="options">自由配置项</param>
    /// <param name="isAuthor">是否授权</param>
    /// <param name="schemeName">默认 Bearer </param>
    public static IServiceCollection AddSwaggerGen(this IServiceCollection services, List<DocVersions> versions, Action<SwaggerGenOptions> options, bool isAuthor = false, string schemeName = "Bearer")
    {
        services.AddSwaggerGen(c =>
        {
            foreach (var v in versions)
            {
                c.SwaggerDoc(v.Version, new OpenApiInfo()
                {
                    Title = $"{v.Title} - {RuntimeInformation.FrameworkDescription}",
                    Version = v.Version,
                });
            }

            options.Invoke(c);

            c.DocumentFilter<SwaggerApi>();
            if (isAuthor)
            {
                c.AddSecurityDefinition(schemeName, new OpenApiSecurityScheme
                {
                    Type = SecuritySchemeType.Http,
                    Name = "Authorization",
                    Description = "JWT Authorization header using the Bearer scheme.",
                    BearerFormat = "JWT",
                    Scheme = schemeName.ToLower(),
                    In = ParameterLocation.Header,
                });

                c.AddSecurityRequirement(new OpenApiSecurityRequirement {
                {
                    new OpenApiSecurityScheme{
                        Reference =new  OpenApiReference{
                            Type=ReferenceType.SecurityScheme,
                            Id=schemeName
                        }
                    },
                    new string[]{ }
                }
            });
            }
        });
        return services;
    }



    /// <summary>
    /// 添加 SwaggerUI 默认文档合并
    /// </summary>
    /// <param name="app"></param>
    /// <param name="title">配置文档标题</param>
    /// <param name="versions"></param>
    public static IApplicationBuilder AddSwaggerUI(this IApplicationBuilder app, string title, List<DocVersions> versions)
    {

        if (app == null) throw new ArgumentNullException(nameof(app));

        app.UseSwagger();
        // 配置 Swagger UI 参数
        app.UseSwaggerUI(options =>
        {
            // 配置文档标题
            options.DocumentTitle = title;// "RuoVea 接口文档";
            //// 配置UI地址（处理二级虚拟目录）
            //options.RoutePrefix = "doc";
            foreach (var v in versions) options.SwaggerEndpoint("/swagger/" + v.Version + "/swagger.json", v.Title);
            // 文档展开设置
            options.DocExpansion(Swashbuckle.AspNetCore.SwaggerUI.DocExpansion.None);
            var xmlPath = Path.Combine(AppContext.BaseDirectory, "index.html");//index-mini-profiler
            FileStream fileStream = new FileStream(xmlPath, FileMode.Open);
            options.IndexStream = (Func<Stream>)(() => fileStream);
            // 配置多语言和自动登录token
            options.UseRequestInterceptor("(request) => { return defaultRequestInterceptor(request); }");
            options.UseResponseInterceptor("(response) => { return defaultResponseInterceptor(response); }");
        });

        // 增加支持静态资源访问 
        app.UseStaticFiles();

        return app;
    }
}
